package com.atguigu.gmall.activity.controller;

import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.user.UserAddress;
import com.atguigu.gmall.order.client.OrderFeignClient;
import com.atguigu.gmall.user.client.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author mqx
 * http://activity.atguigu.cn/seckill.html
 * @date 2020-10-28 10:52:23
 */
@RestController
@RequestMapping("/api/activity/seckill")
public class SeckillGoodsApiController {

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private OrderFeignClient orderFeignClient;

    //  查询所有
    @GetMapping("/findAll")
    public Result findAll(){
        List<SeckillGoods> seckillGoodsList = seckillGoodsService.findAll();

        return Result.ok(seckillGoodsList);
    }
    //  商品详情
    @GetMapping("/getSeckillGoods/{skuId}")
    public Result getSeckillGoods(@PathVariable Long skuId){
        //  返回数据
        return Result.ok(seckillGoodsService.getSeckillGoods(skuId));
    }
    //  http://api.gmall.com/api/activity/seckill/auth/getSeckillSkuIdStr/29
    @GetMapping("auth/getSeckillSkuIdStr/{skuId}")
    public Result getSeckillSkuIdStr(@PathVariable Long skuId, HttpServletRequest request){
        //  下单码组成：使用用户Id ，对其继续加密
        String userId = AuthContextHolder.getUserId(request);
        //  什么时候才能获取下单！必须在秒杀活动期间，
        SeckillGoods seckillGoods = seckillGoodsService.getSeckillGoods(skuId);
        if (seckillGoods!=null){
            //  当前时间必须在秒杀开始之后，结束之前！
            Date curTime = new Date();
            if (DateUtil.dateCompare(seckillGoods.getStartTime(),curTime)
            && DateUtil.dateCompare(curTime,seckillGoods.getEndTime())){
                //  生成下单码
                String encrypt = MD5.encrypt(userId);
                //  返回下单码
                return Result.ok(encrypt);
            }
        }
        return Result.fail().message("获取下单码失败！");
    }

    //  下单的校验
    //  queue.html  seckillOrder()  url: this.api_name + '/auth/seckillOrder/' + skuId + '?skuIdStr=' + skuIdStr
    @PostMapping("auth/seckillOrder/{skuId}")
    public Result seckillOrder(@PathVariable Long skuId,HttpServletRequest request){
        //  获取userId
        String userId = AuthContextHolder.getUserId(request);
        //  从页面获取下单码
        String skuIdStr = request.getParameter("skuIdStr");
        //  校验下单码
        if (!skuIdStr.equals(MD5.encrypt(userId))){
            return Result.build(null, ResultCodeEnum.SECKILL_ILLEGAL);
        }
        //  校验状态位state
        String state = (String) CacheHelper.get(skuId.toString());
        //  判断状态位
        if ("0".equals(state)){
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }else if ("1".equals(state)){
            //  能抢购，发送消息
            //  将数据记录到UserRecode
            UserRecode userRecode = new UserRecode();
            userRecode.setSkuId(skuId);
            userRecode.setUserId(userId);
            //  发送到mq 中！到 这个位置，那么只能说明，你有资格，但是抢不抢的到，那要看运气！
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_SECKILL_USER,MqConst.ROUTING_SECKILL_USER,userRecode);
        }else {
            return Result.build(null, ResultCodeEnum.SECKILL_ILLEGAL);
        }
        //  返回
        return Result.ok();
    }

    @GetMapping(value = "auth/checkOrder/{skuId}")
    public Result checkOrder(@PathVariable Long skuId,HttpServletRequest request){
        // 获取用户id,目的校验
        String userId = AuthContextHolder.getUserId(request);

        //  调用服务层的方法。前台页面需要data ，code.
        return seckillGoodsService.checkOrder(skuId,userId);
    }
    //  这个控制器应该发布到feign 上，然后由web-all 调用。
    @GetMapping("auth/trade")
    public Result trade(HttpServletRequest request){
        //  数据渲染
        //  获取用户Id
        String userId = AuthContextHolder.getUserId(request);

        //  获取到收货地址列表
        List<UserAddress> userAddressList = userFeignClient.findUserAddressListByUserId(userId);
        //  获取用户的订单明细，获取秒杀的商品！
        String orderKey = RedisConst.SECKILL_ORDERS;
        //  hget(key,field);
        OrderRecode orderRecode = (OrderRecode) redisTemplate.boundHashOps(orderKey).get(userId);
        //  判断
        if(orderRecode==null){
            return Result.fail().message("非法操作");
        }
        //  用户秒杀的时候，将秒杀上存到那了? seckillGoods 属性中
        SeckillGoods seckillGoods = orderRecode.getSeckillGoods();
        //  给订单明细赋值！
        OrderDetail orderDetail = new OrderDetail();
        //  声明一个集合来存储orderDetail ;
        ArrayList<OrderDetail> detailArrayList = new ArrayList<>();
        if (seckillGoods!=null){
            // OrderDetail orderDetail = new OrderDetail();
            orderDetail.setSkuId(seckillGoods.getSkuId());
            orderDetail.setSkuName(seckillGoods.getSkuName());
            orderDetail.setImgUrl(seckillGoods.getSkuDefaultImg());
            orderDetail.setSkuNum(orderRecode.getNum());
            orderDetail.setOrderPrice(seckillGoods.getCostPrice());
        }
        //  添加订单明细
        detailArrayList.add(orderDetail);
        //  计算总价格
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderDetailList(detailArrayList);
        orderInfo.sumTotalAmount();

        Map<String, Object> result = new HashMap<>();
        result.put("detailArrayList",detailArrayList);
        result.put("userAddressList",userAddressList);
        result.put("totalAmount",orderInfo.getTotalAmount());

        //  返回数据！
        return Result.ok(result);
    }

    //  url： /api/activity/seckill/auth/submitOrder
    @PostMapping("auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfo orderInfo,HttpServletRequest request){
        //  获取用户Id
        String userId = AuthContextHolder.getUserId(request);
        //  赋值用户Id
        orderInfo.setUserId(Long.parseLong(userId));

        //  做判断！    什么情况下保存，什么去情况下不用保存?
        String orderKey =  RedisConst.SECKILL_ORDERS;
        OrderRecode orderRecode = (OrderRecode) redisTemplate.boundHashOps(orderKey).get(userId);
        //  如果没有订单记录，
        if (orderRecode==null){
            return Result.fail().message("非法操作");
        }
        //  调用服务层保存方法,将数据保存到数据库！ submitOrder() 会调用orderService.saveOrderInfo();
        //  重新编写一个方法 保存完成之后，应该会跳转到支付页面！后面需要一个订单Id
        Long orderId =  orderFeignClient.submitOrder(orderInfo);
        if (orderId==null){
            return Result.fail().message("下单失败，请重新操作");
        }

        //  将用户下过的订单信息保存到缓存中！
        //  如果用户下过订单，那么应该在缓存中有存储记录！
        //  Hash hset(key,field,value)  key = RedisConst.SECKILL_ORDERS_USERS field = userId value = orderId
        redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).put(userId,orderId.toString());

         /*
        1.  userId = 1 , 第一次秒杀，预下单记录 key = RedisConst.SECKILL_ORDERS field = userId value = orderRecode
        2.  将数据保存到数据库中，同时将数据保存到缓存！ Hash hset(key,field,value)  key = RedisConst.SECKILL_ORDERS_USERS field = userId value = orderId

        3.  如果用户 第二次进来。提示已经秒杀成功，查看订单，为了保证这个效果出现，那么我们在第一次下订单成功时，将RedisConst.SECKILL_ORDERS 删掉！

         */
        //删除下单信息
        redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).delete(userId);

        return Result.ok(orderId);

    }


}
